﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Iesi.Collections.Generic;
using Ornament.MemberShip.Permissions;
using System.Linq;

namespace Ornament.MemberShip
{
    /// <summary>
    /// 组织单元，越上层的组织单元，自动继承下级单元的角色
    /// </summary>
    [Serializable]
    public class Org : Member,IPerformer
    {
        private const string BaseMaxOrderId = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
        private const string BaseMinOrderId = "00000000-0000-0000-0000-000000000000";
        private Iesi.Collections.Generic.ISet<Org> childs;
        private string orderId;
        private Org parent;

        protected Org()
        {
        }
        public Org(string name) : base(name) { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        public Org(Guid id)
        {
            Id = id;
        }

        /// <summary>
        /// 
        /// </summary>
        public virtual Org Parent
        {
            get { return parent; }
        }

        /// <summary>
        /// 
        /// </summary>
        protected virtual Iesi.Collections.Generic.ISet<Org> Childs
        {
            get
            {
                if (childs == null)
                    childs = new HashedSet<Org>();
                return childs;
            }
            set { childs = value; }
        }

        public virtual int OrgCount
        {
            get { return Childs.Count; }
        }

        /// <summary>
        /// 
        /// </summary>
        public virtual string OrderId
        {
            get { return orderId; }
        }

        public virtual ReadOnlyCollection<Org> Orgs
        {
            get
            {
                var a = new List<Org>(Childs);
                return new ReadOnlyCollection<Org>(a);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="childOrg"></param>
        public virtual void Add(Org childOrg)
        {
            /* 1 检查child是否为空，检查 child是否已经保存过数据库.child必须不能体属于任何一个ParentOrg
             * 2 检查现在的对象及父节点必须已经拥有Id            
             * 3 更新child下所有的子的OrderId，为childOrg的parent赋值
             * 4 创建当前的Orderid
             * */
            //1
            if (childOrg == this)
                throw new ArgumentException("Org can not add self");
            if (childOrg == null)
                throw new ArgumentNullException("childOrg");
            if (childOrg.Id == Guid.Empty)
                throw new ArgumentNullException("childOrg", "org's Id must have value before being added");
            if (childOrg.parent != null)
                throw new ArgumentException("org must not be belong to some parent");
            //if childOrg is current org's parent ,it throw exception;
            if (OrderId != null && OrderId.IndexOf(childOrg.Id.ToString()) != -1)
                throw new ArgumentException("org can't add it's parent org");


            //2
            if (Id == Guid.Empty)
                throw new ArgumentException("save it before add child org");
            if (parent != null && parent.Id == Guid.Empty)
                throw new ArgumentException("Before add child org ,Org's Id must have value");

            //3
            childOrg.parent = this;
            if (String.IsNullOrEmpty(OrderId))
                childOrg.orderId = Id.ToString();
            else
                childOrg.orderId = OrderId + "." + Id;
            Childs.Add(childOrg);
            ChangeNewParent(childOrg.Childs, childOrg.orderId + "." + childOrg.Id);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="org"></param>
        public virtual void Remove(Org org)
        {
            if (org == null)
                throw new ArgumentNullException("org");
            if (!childs.Contains(org))
            {
                throw new ArgumentOutOfRangeException("org", "It not belong to this");
            }
            if (Childs.Remove(org))
            {
                org.orderId = null;
                org.parent = null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="org"></param>
        /// <returns></returns>
        public virtual bool Contains(Org org)
        {
            if (org == null) throw new ArgumentNullException("org");

            return Childs.Contains(org);
        }

      

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public virtual bool LevelUp()
        {
            if (Parent == null)
                return false;
            if (parent.parent == null)
            {
                parent.Remove(this);
            }
            else
            {
                parent.Remove(this);
                parent.parent.Add(this);
            }
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="newParent"></param>
        /// <returns></returns>
        public virtual bool LevelDown(Org newParent)
        {
            if (parent != null)
                parent.Remove(this);

            try
            {
                newParent.Add(this);
                return true;
            }
            catch (ArgumentException ex)
            {
                if (ex.Message == "org can't add it's parent org")
                    throw new ArgumentException("newParent is it's child,can't be LevelDown");
                throw;
            }
        }
        private Iesi.Collections.Generic.ISet<Permission> _permissions;

        public virtual IEnumerable<Permission> Permissions
        {
            get
            {
                if (_permissions == null)
                {
                    _permissions=new HashedSet<Permission>();
                    foreach(var role in this.Roles)
                    {
                        _permissions.AddAll(role.Permissions);
                    }
                }
                return _permissions;
            }         
        }

     
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static void CreateGetChildCondition(Org org, out string maxOrderId, out string minOrderid)
        {
            if (org == null)
                throw new ArgumentNullException("org");
            if (org.Id == Guid.Empty)
            {
                throw new ArgumentException("org.Id");
            }
            minOrderid = !String.IsNullOrEmpty(org.OrderId) ? org.OrderId + "." + BaseMinOrderId : BaseMinOrderId;
            maxOrderId = !String.IsNullOrEmpty(org.orderId) ? org.OrderId + "." + BaseMaxOrderId : BaseMaxOrderId;
        }

        private static void ChangeNewParent(IEnumerable<Org> childOrg, string newParentOrderId)
        {
            foreach (Org org in childOrg)
            {
                org.orderId = newParentOrderId;
                if (org.Childs.Count != 0)
                    ChangeNewParent(org.Childs, newParentOrderId + "." + org.Id);
            }
        }

        public virtual ReadOnlyCollection<Org> GetAllChilds()
        {
            IList<Org> orgs = new List<Org>(Childs);
            return new ReadOnlyCollection<Org>(orgs);
        }

        IList<User> IPerformer.GetUsers(IMemberShipFactory memberShip)
        {
            var a= from user in memberShip.Users where user.Org == this select user;
            return a.ToList<User>();
        }

        
    }
}